package de.Hijack.Giuliani;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import java.util.ArrayList;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Vibrator;
import android.util.Log;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.Toast;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;

import java.util.Collections;

/**
 * 
 * @author Bastian Hinterleitner
 */
public class WayPointOverlay extends Overlay {

    private static final String TAG = "WayPointOverlay";
    //target Point
    ArrayList<WayPoint> wayPoints_graphics = new ArrayList<WayPoint>();
    private Point NEW_POINT = new Point();
    //Drawing objects
    private MainMapActivity context;
    private DBAdapter adapter;
    private Bitmap landmark;
    private Bitmap redpin;
    // variables for the long-click action
    private long lastClicked = 0;
    private Point lastClickedPosition = new Point(0, 0);
    private static final long LONGCLICKTIME = 500;

    public WayPointOverlay(MainMapActivity c, DBAdapter a) {
        super();
        this.context = c;
        this.adapter = a;
        landmark = BitmapFactory.decodeResource(context.getResources(), R.drawable.landmark);
        redpin = BitmapFactory.decodeResource(context.getResources(), R.drawable.redpin);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e, MapView m) {
        // tolerance because you most likely wont exactly click the point
        int tolerance = 20;
        switch (e.getAction()) {
            // only do sth if you press it, not if you move the map
            case MotionEvent.ACTION_DOWN:
                // long click things:
                lastClicked = System.currentTimeMillis();
                lastClickedPosition = new Point((int) e.getX(), (int) e.getY());
                
                final ArrayList<WayPoint> points = new ArrayList<WayPoint>();
                Log.d(TAG, "clicked at: " + e.getX() + ", " + e.getY());
                
                // check which points were clicked and add them to "points"
                for (WayPoint point : wayPoints_graphics) {
                    m.getProjection().toPixels(point, NEW_POINT);
                    if (e.getX() < NEW_POINT.x + tolerance && e.getX() > NEW_POINT.x - tolerance
                            && e.getY() < NEW_POINT.y && e.getY() > NEW_POINT.y - 2 * tolerance) {
                        if ((context.mode == MainMapActivity.MODE_GPS && point.measurement == null)
                        || (context.mode == MainMapActivity.MODE_REDPIN && point.measurement != null)) {
                            if(point.floor==context.maps.getFloor()||context.mode!=MainMapActivity.MODE_REDPIN)points.add(point);
                        }
                    }
                }

                // if only one was clicked dont show the list
                if (points.size() == 1) {
                    final WayPoint point = points.get(0);
                    AlertDialog a = new AlertDialog.Builder(context).create();
                    a.setTitle("GeoPunkt:");
                    a.setMessage("lat: " + point.getLatitudeE6() + "\nlong:" + point.getLongitudeE6());
                    final EditText edit = new EditText(context);
                    edit.setText(point.getDescription());
                    a.setView(edit);
                    a.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new OnClickListener() {

                        public void onClick(DialogInterface arg0, int arg1) {
                            point.setDescription(edit.getText().toString());
                            adapter.apply(point);
                            wayPoints_graphics = adapter.getPoints();
                        }
                    });
                    a.setButton(AlertDialog.BUTTON_NEGATIVE, "Loeschen", new OnClickListener() {

                        public void onClick(DialogInterface arg0, int arg1) {
                            adapter.delete(point);
                            wayPoints_graphics = adapter.getPoints();
                        }
                    });
                    a.show();
                } else { // show a list of points clicked
                    if (points.size() > 1) {

                        String[] names = new String[points.size()];

                        // shortening the too long names and adding a "..." at the end
                        for (int i = 0; i < names.length; i++) {
                            names[i] = "";
                            for (int j = 0; j < 10 && j < points.get(i).toString().length(); j++) {
                                names[i] += points.get(i).toString().charAt(j);
                            }
                            names[i] += "...";
                        }

                        AlertDialog.Builder builder = new AlertDialog.Builder(context);
                        builder.setTitle("GeoPunkte");
                        builder.setItems(names, new DialogInterface.OnClickListener() {

                            public void onClick(DialogInterface dialog, int item) {
                                final WayPoint point = points.get(item);
                                AlertDialog a = new AlertDialog.Builder(context).create();
                                a.setTitle("GeoPunkt:");
                                a.setMessage("lat: " + point.getLatitudeE6() + "\nlong:" + point.getLongitudeE6());
                                final EditText edit = new EditText(context);
                                edit.setText(point.getDescription());
                                a.setView(edit);
                                a.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new OnClickListener() {

                                    public void onClick(DialogInterface arg0, int arg1) {
                                        point.setDescription(edit.getText().toString());
                                        adapter.apply(point);
                                        wayPoints_graphics = adapter.getPoints();
                                    }
                                });
                                a.setButton(AlertDialog.BUTTON_NEGATIVE, "Loeschen", new OnClickListener() {

                                    public void onClick(DialogInterface arg0, int arg1) {
                                        adapter.delete(point);
                                        wayPoints_graphics = adapter.getPoints();
                                        context.update();
                                    }
                                });
                                a.show();
                            }
                        }).show();
                    }
                }
                break;
        }

        // check whether a long click action was performed
        if (System.currentTimeMillis() - lastClicked > LONGCLICKTIME && distance(lastClickedPosition, e) < tolerance) {
            try {
                ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50);
            } catch (Exception ex) {
                Log.e(TAG, "no vibrator installed!");
            }
            savePosition(new WayPoint(m.getProjection().fromPixels((int) e.getX(), (int) e.getY())));
            lastClicked = System.currentTimeMillis();
            lastClickedPosition = new Point(0, 0);
        }

        return super.onTouchEvent(e, m);
    }

    private int distance(Point p, MotionEvent e) {
        int distance = (int) Math.abs(p.x - e.getX());
        distance += (int) Math.abs(p.y - e.getY());
        return distance / 2;
    }

    void savePosition(WayPoint p) {
        if (context.mode == MainMapActivity.MODE_REDPIN) {
            if (context.lastKnownMeasurement != null) {
                p.measurement = context.lastKnownMeasurement;
                p.floor = context.maps.getFloor();
            } else {
                Toast.makeText(context, "keine Netzwerke gefunden!! (Wifi an?)", Toast.LENGTH_SHORT).show();
                return;
            }
        }
        adapter.addPoint(p);
        wayPoints_graphics = adapter.getPoints();
        context.update();
    }

    //Method to mark the target on MapViewActivity
    @Override
    public void draw(Canvas canvas, MapView mapView, boolean shadow) {
        super.draw(canvas, mapView, shadow);

        //Draw WayPoints
        Collections.sort(wayPoints_graphics);

        for (WayPoint target : wayPoints_graphics) {

            //final GeoPoint target = KneipenMapActivity.target;
            mapView.getProjection().toPixels(target, NEW_POINT);

            //Log.d(TAG, "drawing point at: "+NEW_POINT.x+", "+ NEW_POINT.y);

            if (!(NEW_POINT.x < 0 || NEW_POINT.y < 0 || NEW_POINT.x > ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth() || NEW_POINT.y > ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight())) {
                Paint paint = new Paint();
                //draw them transparent if the wrong mode is active
                if ((context.mode == MainMapActivity.MODE_GPS && target.measurement == null)
                        || (context.mode == MainMapActivity.MODE_REDPIN && target.measurement != null)) {
                    paint.setAlpha(255);
                }else{
                    paint.setAlpha(20);
                }
                if (target.measurement == null) {
                    canvas.drawBitmap(landmark, NEW_POINT.x - 24, NEW_POINT.y - 48, paint);
                } else {
                    if(target.floor==context.maps.getFloor())canvas.drawBitmap(redpin, NEW_POINT.x - 24, NEW_POINT.y - 48, paint);
                }
            }
        }

    }

    /**
     * adds points to the map
     * @param points 
     */
    void addPoints(ArrayList<WayPoint> points) {
        Log.d(TAG, "adding points:");
        for (int i = 0; i < points.size(); i++) {
            Log.d(TAG, "added point");
            wayPoints_graphics.add(points.get(i));
        }
    }
}
